﻿//PowerShell WMI Provider by Roger Zander

using System.Collections;
using System.Management.Instrumentation;
using System.Management;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;


[assembly: WmiConfiguration(@"root\cimv2", HostingModel = ManagementHostingModel.LocalSystem)]
namespace PSProvider
{
    [System.ComponentModel.RunInstaller(true)]
    public class MyInstall : DefaultManagementInstaller
    {
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
            System.Runtime.InteropServices.RegistrationServices RS = new System.Runtime.InteropServices.RegistrationServices();

            try
            {
                new System.EnterpriseServices.Internal.Publish().GacInstall(System.Reflection.Assembly.GetExecutingAssembly().Location);
            }
            catch { }
        }

        public override void Uninstall(IDictionary savedState)
        {

            try
            {
                ManagementClass MC = new ManagementClass(@"root\cimv2:Win32_PSProvider");
                MC.Delete();
            }
            catch { }

            try
            {
                base.Uninstall(savedState);
            }
            catch { }

            try
            {
                new System.EnterpriseServices.Internal.Publish().GacRemove(System.Reflection.Assembly.GetExecutingAssembly().Location);
            }
            catch { }
        }
    }

    [ManagementEntity(Name = "Win32_PSProvider")]
    public class PSProvider
    {
        [ManagementKey]
        public string Path { get; set; }

        [ManagementProbe]
        public string Value { get; set; }

        /// <summary>
        /// The Constructor to create new instances of the LocalAdmins class...
        /// </summary>
        public PSProvider(string sPath, string sValue)
        {
            Path = sPath;
            Value = sValue;
        }

        /// <summary>
        /// This Function returns all members of the local Administrators group
        /// </summary>
        /// <returns></returns>
        [ManagementEnumerator]
        static public IEnumerable GetItems()
        {
            string sFile = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Wbem\PSWMIProvider.ps1");
            if (!File.Exists(sFile))
                yield return null;

            Collection<PSObject> oResults = _RunPS(File.ReadAllText(sFile));
            foreach (var oPS in oResults)
            {
                string sPath = "";
                List<string> lProps = new List<string>();

                //detect WMI Objects
                if (oPS.Properties["__PATH"] != null)
                {
                    sPath = oPS.Properties["__PATH"].Value.ToString();
                    sPath = sPath.Replace(Environment.MachineName + "\\", "");
                    sPath = sPath.Replace("\\", "/").Replace(":", "/").Replace("//", "");
                    string sKey = sPath.Substring(sPath.IndexOf("."), sPath.IndexOf("=") - sPath.IndexOf("."));

                    sPath = sPath.Replace(sKey, "").Replace("=\"", "/").Replace("\"", "").Replace("=@", "").Replace(" ", "").Split(',')[0];

                    //Get all the Properties of the Object
                    PropertyDataCollection oProps = oPS.Properties["Properties"].Value as PropertyDataCollection;

                    foreach (PropertyData PD in oProps)
                    {
                        lProps.Add(PD.Name);
                    }

                    foreach (var oProp in oPS.Properties)
                    {
                        if (lProps.Contains(oProp.Name))
                        {
                            if (oProp.Value != null)
                            {
                                if (oProp.TypeNameOfValue == "System.String[]")
                                {
                                    int i = 0;
                                    foreach (string sChildProp in oProp.Value as string[])
                                    {
                                        yield return new PSProvider(sPath + "/" + oProp.Name + "/" + i.ToString(), sChildProp);
                                        //Console.WriteLine(sPath + "/" + oProp.Name + "/" + i.ToString() + " == " + sChildProp);
                                        i++;
                                    }
                                }

                                if (oProp.TypeNameOfValue != "System.String[]")
                                {
                                    //Console.WriteLine(sPath + "/" + oProp.Name + " == " + oProp.Value.ToString());
                                    yield return new PSProvider(sPath + "/" + oProp.Name, oProp.Value.ToString());
                                }
                            }
                        }
                    }
                }

                //NON WMI Objects
                else
                {
                    sPath = oPS.BaseObject.ToString();
                    //Get all the Properties of the Object
                    string sKey = "";
                    try
                    {
                        sKey = oPS.Properties.FirstOrDefault(t => t.Name == "ObjPath").Value as string;
                    }
                    catch { }

                    if (string.IsNullOrEmpty(sKey))
                    {
                        sKey = oPS.Properties.First(t => !t.Name.StartsWith("__")).Value.ToString();
                    }

                    //sKey = sKey.Replace("//", ""); //Replace(":", "/")
                    Dictionary<string, string> pdc = new Dictionary<string, string>();

                    foreach (var PD in oPS.Properties)
                    {
                        if (PD.Name == "ObjPath")
                            continue;
                        try
                        {
                            pdc.Add(sKey + "\\" + PD.Name, PD.Value.ToString());
                        }
                        catch { }
                    }

                    foreach(var oRes in pdc)
                    {
                        yield return new PSProvider(oRes.Key,oRes.Value);
                    }
                }
            }
        }

        public static Collection<PSObject> _RunPS(string PSScript)
        {
            PowerShell PowerShellInstance = PowerShell.Create();

            PowerShellInstance.AddScript(PSScript);

            Collection<PSObject> PSOutput = PowerShellInstance.Invoke();

            return PSOutput;

        }

    }

}
